﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SouthApps.MobileTasks.SDK.DAL.Repositories;
using SouthApps.MobileHealth.SDK.DAL;
using SouthApps.MobileHealth.SDK.DAL.Model;
using SouthApps.MobileHealth.SDK.Utils;
using SouthApps.MobileHealth.SDK.Cache;

namespace SouthApps.MobileHealth.SDK.Services
{
    public class FinanciadoresService
    {
        private IPrestadoresRepository prestadoresRepository;
        private IFinanciadoresRepository financiadoresRepository;

        public FinanciadoresService()
        {
            this.prestadoresRepository = new PrestadoresRepository();
            this.financiadoresRepository = new FinanciadoresRepository();
        }

        public List<ServicioEspecial> GetServiciosEspeciales()
        {
            return this.financiadoresRepository.GetServiciosEspeciales();
        }

        public List<ServicioEspecial> GetServiciosEspecialesLocaciones(int financiadorId)
        {
            return this.financiadoresRepository.GetServiciosEspecialesLocaciones(financiadorId);
        }

        public List<ServicioGuardia> GetServiciosGuardiaFinanciador(int financiadorId)
        {
            return this.financiadoresRepository.GetServiciosGuardiaFinanciador(financiadorId);
        }

        public List<Financiador> GetFinanciadores()
        {
            return this.financiadoresRepository.GetFinanciadores();
        }

        public Financiador GetFinanciador(int financiadorId)
        {
            return this.financiadoresRepository.GetFinanciador(financiadorId);
        }

        public void AddPrestador(Prestador prestador)
        {
            this.prestadoresRepository.AddPrestador(prestador);
        }

        public void AddSucursalPrestador(int financiadorId, SucursalPrestador sucursalPrestador)
        {
            this.prestadoresRepository.AddSucursalPrestador(financiadorId, sucursalPrestador);
        }

        public List<ExtendedSucursalPrestador> GetSucursalesPrestadorPorCercania(int financiadorId, int especialidadId, int planId, Location location, int pageNumber, int pageSize, out int totalCount)
        {
            List<SucursalPrestador> sucursalesCercanas = SucursalesPrestadorCache.GetSucursalesPrestador(financiadorId, especialidadId, planId);

            if (sucursalesCercanas.Count == 0)
            {
                totalCount = 0;
                return new List<ExtendedSucursalPrestador>();
            }

            List<ExtendedSucursalPrestador> extendedSucursalesCercanas = this.GetExtendedSucursalPrestadorList(sucursalesCercanas, location);

            extendedSucursalesCercanas.Sort(delegate(ExtendedSucursalPrestador sucursalPrestadorA, ExtendedSucursalPrestador sucursalPrestadorB)
            {
                return (sucursalPrestadorA.DistanciaAReferencia >= sucursalPrestadorB.DistanciaAReferencia) ? 1 : -1;
            });

            totalCount = extendedSucursalesCercanas.Count;

            int startRow = (pageNumber - 1) * pageSize;
            var sucursalesCercanasPaginadas = (from e in extendedSucursalesCercanas
                                               select e).Skip(startRow).Take(pageSize).ToList();

            return sucursalesCercanasPaginadas;
        }

        public List<SucursalPrestador> GetSucursalesPrestadorPorZona(int financiadorId, int especialidadId, int planId, int departamentoId)
        {
            List<SucursalPrestador> sucursalesPorZona = SucursalesPrestadorCache.GetSucursalesPrestador(financiadorId, especialidadId, planId, departamentoId);

            if (sucursalesPorZona.Count == 0)
            {
                return sucursalesPorZona;
            }

            return sucursalesPorZona;
        }

        public List<ExtendedGuardiaSucursalPrestador> GetGuardiasSucursalesPrestadorPorCercania(int financiadorId, int? servicioGuardiaId, Location location, int pageNumber, int pageSize, out int totalCount)
        {
            List<GuardiaSucursalPrestador> guardiasSucursalesPrestadorCercanas = GuardiasSucursalPrestadorCache.GetGuardiasSucursalesPrestador(financiadorId, servicioGuardiaId);

            if (guardiasSucursalesPrestadorCercanas.Count == 0)
            {
                totalCount = 0;
                return new List<ExtendedGuardiaSucursalPrestador>();
            }

            List<ExtendedGuardiaSucursalPrestador> extendedGuardiasSucursalesCercanas = this.GetExtendedGuardiaSucursalPrestadorList(guardiasSucursalesPrestadorCercanas, location);

            extendedGuardiasSucursalesCercanas.Sort(delegate(ExtendedGuardiaSucursalPrestador guardiaSucursalPrestadorA, ExtendedGuardiaSucursalPrestador guardiaSucursalPrestadorB)
            {
                return (guardiaSucursalPrestadorA.DistanciaAReferencia >= guardiaSucursalPrestadorB.DistanciaAReferencia) ? 1 : -1;
            });

            totalCount = extendedGuardiasSucursalesCercanas.Count;

            int startRow = (pageNumber - 1) * pageSize;
            var guardiasSucursalesCercanasPaginadas = (from e in extendedGuardiasSucursalesCercanas
                                               select e).Skip(startRow).Take(pageSize).ToList();

            return guardiasSucursalesCercanasPaginadas;
        }

        public List<GuardiaSucursalPrestador> GetGuardiasSucursalesPrestadorPorZona(int financiadorId, int? servicioGuardiaId, int departamentoId)
        {
            List<GuardiaSucursalPrestador> guardiasSucursalesPrestadorPorZona = GuardiasSucursalPrestadorCache.GetGuardiasSucursalesPrestador(financiadorId, servicioGuardiaId, departamentoId);

            return guardiasSucursalesPrestadorPorZona;
        }

        public List<LocacionServicioEspecial> GetLocacionesServicioEspecialPorCercania(int financiadorId, int servicioEspecialId, Location location, int pageNumber, int pageSize, out int totalCount)
        {
            List<LocacionServicioEspecial> locacionesServiciosEspecialesCercanos = LocacionesServicioEspecialCache.GetLocacionesServicioEspecial(financiadorId, servicioEspecialId);

            if (locacionesServiciosEspecialesCercanos.Count == 0)
            {
                totalCount = 0;
                return locacionesServiciosEspecialesCercanos;
            }

            locacionesServiciosEspecialesCercanos.Sort(delegate(LocacionServicioEspecial locacionServicioEspecial1, LocacionServicioEspecial locacionServicioEspecial2)
            {
                Location locacionServicioEspecialA = new Location(locacionServicioEspecial1.latitud, locacionServicioEspecial1.longitud);
                Location locacionServicioEspecialB = new Location(locacionServicioEspecial2.latitud, locacionServicioEspecial2.longitud);

                return DistanceCalculator.GetDistance(location, locacionServicioEspecialA) >= DistanceCalculator.GetDistance(location, locacionServicioEspecialB) ? 1 : -1;
            });

            totalCount = locacionesServiciosEspecialesCercanos.Count;
               
            int startRow = (pageNumber - 1) * pageSize;
            var locacionesServiciosEspecialesCercanosPaginados = (from e in locacionesServiciosEspecialesCercanos
                                                       select e).Skip(startRow).Take(pageSize).ToList();

            return locacionesServiciosEspecialesCercanosPaginados;
        }

        public List<LocacionServicioEspecial> GetLocacionesServicioEspecialPorZona(int financiadorId, int servicioEspecialId, int departamentoId)
        {
            List<LocacionServicioEspecial> locacionesServicioEspecialPorZona = LocacionesServicioEspecialCache.GetLocacionesServicioEspecial(financiadorId, departamentoId, servicioEspecialId);

            return locacionesServicioEspecialPorZona;
        }

        public List<ExtendedCentroAtencion> GetCentrosAtencionPorCercania(int financiadorId, Location location, int pageNumber, int pageSize, out int totalCount)
        {
            List<CentroAtencion> centrosAtencionCercanos = CentrosAtencionCache.GetCentrosAtencion(financiadorId);

            if (centrosAtencionCercanos.Count == 0)
            {
                totalCount = 0;
                return new List<ExtendedCentroAtencion>();
            }

            List<ExtendedCentroAtencion> extendedCentrosAtencionCercanos = this.GetExtendedCentroAtencionList(centrosAtencionCercanos, location);

            extendedCentrosAtencionCercanos.Sort(delegate(ExtendedCentroAtencion centroAtencionA, ExtendedCentroAtencion centroAtencionB)
            {
                return (centroAtencionA.DistanciaAReferencia >= centroAtencionB.DistanciaAReferencia) ? 1 : -1;
            });

            totalCount = extendedCentrosAtencionCercanos.Count;

            int startRow = (pageNumber - 1) * pageSize;
            var centrosAtencionCercanosPaginados = (from e in extendedCentrosAtencionCercanos
                                                                  select e).Skip(startRow).Take(pageSize).ToList();

            return centrosAtencionCercanosPaginados;
        }

        public List<CentroAtencion> GetCentrosAtencionPorZona(int financiadorId, int departamentoId)
        {
            List<CentroAtencion> centrosAtencionPorZona = CentrosAtencionCache.GetCentrosAtencion(financiadorId, departamentoId);

            return centrosAtencionPorZona;
        }

        private List<ExtendedSucursalPrestador> GetExtendedSucursalPrestadorList(List<SucursalPrestador> sucursalesCercanas, Location sourceLocation)
        {
            List<ExtendedSucursalPrestador> extendedSucursalPrestadorList = new List<ExtendedSucursalPrestador>();

            foreach(SucursalPrestador sucursalPrestador in sucursalesCercanas)
            {
                Location destinationLocation = new Location(sucursalPrestador.latitud, sucursalPrestador.longitud);
                ExtendedSucursalPrestador extendedSucursalPrestador = new ExtendedSucursalPrestador(sucursalPrestador, DistanceCalculator.GetDistance(sourceLocation, destinationLocation));
                extendedSucursalPrestadorList.Add(extendedSucursalPrestador);
            }

            return extendedSucursalPrestadorList;
        }

        private List<ExtendedGuardiaSucursalPrestador> GetExtendedGuardiaSucursalPrestadorList(List<GuardiaSucursalPrestador> guardiasSucursalesCercanas, Location sourceLocation)
        {
            List<ExtendedGuardiaSucursalPrestador> extendedGuardiaSucursalPrestadorList = new List<ExtendedGuardiaSucursalPrestador>();

            foreach (GuardiaSucursalPrestador guardiaSucursalPrestador in guardiasSucursalesCercanas)
            {
                Location destinationLocation = new Location(guardiaSucursalPrestador.sucursalprestador.latitud, guardiaSucursalPrestador.sucursalprestador.longitud);
                ExtendedGuardiaSucursalPrestador extendedGuardiaSucursalPrestador = new ExtendedGuardiaSucursalPrestador(guardiaSucursalPrestador, DistanceCalculator.GetDistance(sourceLocation, destinationLocation));
                extendedGuardiaSucursalPrestadorList.Add(extendedGuardiaSucursalPrestador);
            }

            return extendedGuardiaSucursalPrestadorList;
        }

        private List<ExtendedCentroAtencion> GetExtendedCentroAtencionList(List<CentroAtencion> centroAtencionList, Location sourceLocation)
        {
            List<ExtendedCentroAtencion> extendedCentroAtencionList = new List<ExtendedCentroAtencion>();

            foreach (CentroAtencion centroAtencion in centroAtencionList)
            {
                Location destinationLocation = new Location(centroAtencion.latitud, centroAtencion.longitud);
                ExtendedCentroAtencion extendedCentroAtencion = new ExtendedCentroAtencion(centroAtencion, DistanceCalculator.GetDistance(sourceLocation, destinationLocation));
                extendedCentroAtencionList.Add(extendedCentroAtencion);
            }

            return extendedCentroAtencionList;
        }
    }
}
